2010/09/11

Recent entries from same category

  1. RapidJSON や simdjson よりも速いC言語から使えるJSONライブラリ「yyjson」
  2. コメントも扱える高機能な C++ 向け JSON パーサ「jsoncpp」
  3. C++ で flask ライクなウェブサーバ「clask」書いた。
  4. C++ 用 SQLite3 ORM 「sqlite_orm」が便利。
  5. zsh で PATH に相対パスを含んだ場合にコマンドが補完できないのは意図的かどうか。

以前、twitter上で「STL以上、Boost未満な使い心地のライブラリが欲しい。ネットワーク関連込みの。」とつぶやいた所、id:faith_and_braveさんから返事貰った。
Faith and Brave Twitter / Faith and Brave

CLX or Message-Pack or Pocoあたりでしょうか RT @mattn_jp: STL以上、Boost未満な使い心地のライブラリが欲しい。ネットワーク関連込みの。

http://twitter.com/cpp_akira/status/21234425525
CLXは実は前から知っていて何度か捨てコードに使わせて頂いていたのですが、SSL越しにproxyが使えなかったので、ネットワーク関連のコードには使ってませんでした。
まぁでも一応書いて判断すべきかなと思って、僕的な答えとして、さらーーーっと書いた。
CONSUMER_KEY と CONSUMER_SECRET を書き換えて実行して下さい。xAuth認証を使ってtwitterにステータスをポストします。

#include <iostream>
#include <sstream>
#include <clx/base64.h>
#include <clx/hexdump.h>
#include <clx/date_time.h>
#include <clx/format.h>
#include <clx/hmac.h>
#include <clx/https.h>
#include <clx/random.h>
#include <clx/salgorithm.h>
#include <clx/sha1.h>
#include <clx/uri.h>

std::string url_encode(const std::string& url) {
    std::ostringstream rets;
    for(size_t n = 0; n < url.size(); n++) {
        unsigned char c = (unsigned char)url[n];
        if (isalnum(c) || c == '_' || c == '.' || c == '-')
            rets << c;
        else {
            char buf[8];
            sprintf(buf, "%02X", (int)c);
            rets << '%' << buf[0] << buf[1];
        }
    }
    return rets.str();
}


int main(int argc, char* argv[]) {

    if (argc != 4) {
        std::cerr << "usage: " << argv[0]
            << " [username] [password] [message]" << std::endl;
        return -1;
    }

    clx::date_time now;
    clx::random<unsigned int> randgen;
    randgen.engine().seed(time(0));

    std::string consumer_key = "CONSUMER_KEY";
    std::string consumer_secret = "CONSUMER_SECRET";
    std::string username = argv[1];
    std::string password = argv[2];
    std::string message = argv[3];

    std::stringstream ss;
    std::string times = clx::str(clx::format("%s") % now.c_time());
    std::string nonce = clx::hexdump(times);

    ss << "oauth_consumer_key=" << consumer_key
       << "&oauth_nonce=" << nonce
       << "&oauth_signature_method=" << "HMAC-SHA1"
       << "&oauth_timestamp=" << times
       << "&oauth_version=" << "1.0"
       << "&x_auth_mode=" << "client_auth"
       << "&x_auth_password=" << password
       << "&x_auth_username=" << username;

    std::string key = consumer_secret + "&";
    std::string val = "POST&";

    val += url_encode("https://api.twitter.com/oauth/access_token");
    val += "&";
    val += url_encode(ss.str());
    char* hmac = (char*)clx::hmac<clx::sha1>(
            key.c_str(), key.size(), val.c_str(), val.size()).code();
    std::string hm = clx::base64::encode(hmac, 20);

    ss << "&oauth_signature=" << url_encode(hm);

    clx::https session(clx::uri::encode("api.twitter.com"), 443);
    session.post(clx::uri::encode("/oauth/access_token"), ss.str());

    std::vector<std::string> item;
    std::map<std::string, std::string> params;
    clx::split_if(session.body(), item, clx::is_any_of(LITERAL("&")));
    for (unsigned int i = 0; i < item.size(); i++) {
        std::string tok = item.at(i);
        size_t pos = tok.find_first_of("=");
        params[tok.substr(0, pos)] = clx::uri::decode(tok.substr(pos+1));
    }


    ss.str("");
    ss.clear(std::stringstream::goodbit);

    ss << "oauth_consumer_key=" << consumer_key
       << "&oauth_nonce=" << nonce
       << "&oauth_signature_method=" << "HMAC-SHA1"
       << "&oauth_timestamp=" << times
       << "&oauth_token=" << params["oauth_token"]
       << "&oauth_version=" << "1.0"
       << "&status=" << url_encode(message);

    key = consumer_secret + "&" + params["oauth_token_secret"];
    val = "POST&";

    val += url_encode("https://api.twitter.com/1/statuses/update.json");
    val += "&";
    val += url_encode(ss.str());
    hmac = (char*)clx::hmac<clx::sha1>(
            key.c_str(), key.size(), val.c_str(), val.size()).code();
    hm= clx::base64::encode(hmac, 20);

    ss << "&oauth_signature=" << url_encode(hm);

    session.post(clx::uri::encode("/1/statuses/update.json"), ss.str());
    std::cout << session.body() << std::endl;

    return 0;
}

/* vim:set et sw=4: */
URLまわりと、POSTパラメータ構築に便利なのがあっても良いかなと思った。あーそれboost::asioでも言えるか。
Posted at by